use mlua::{UserData, UserDataMethods};
use super::aead_model::AES;
use crate::models::crypto::aead::{base64_decode, base64_encode, rang_bytes};
use std::collections::HashMap;
use crate::util::util::{AsStr, to_static_str};
use crypto::{sha1,sha2,md5};
use crypto::digest::Digest;
use crate::models::crypto::hash_model::Hash;

#[derive(serde::Deserialize,Clone,serde::Serialize,Default)]
pub struct CryptoModule {}

impl UserData for CryptoModule {
    fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
        methods.add_method("new_aes",|_,_,size:String|{
            Ok(AES::new(size))
        });
        methods.add_method("rang_bytes",|_,_,len:usize|{
            unsafe {
                let src = String::from_utf8_unchecked(rang_bytes(len));
                let s = base64_encode(src.as_bytes());
                let s = to_static_str(s);
                let (res,_) = s.split_at(len);
                Ok(res.to_string())
            }
        });
        methods.add_method("base64_encode",|_,_,src:Vec<u8>|{
            let mut table = HashMap::new();
            let dec = base64_encode(src.as_slice());
            table.insert("output", dec);
            Ok(table)
        });
        methods.add_method("base64_decode",|_,_,src:Vec<u8>|{
            let mut table = HashMap::new();
            match base64_decode(src.as_slice()){
                Ok(o)=> table.insert("output",o.as_str()),
                Err(e)=> table.insert("error",to_static_str(e.to_string())),
            };
            Ok(table)
        });
        methods.add_method("md5",|_,_,src:Vec<u8>|{
            let mut md = md5::Md5::new();
            md.input(src.as_slice());
            let res = md.result_str();
            Ok(res)
        });
        methods.add_method("sha128",|_,_,src:Vec<u8>|{
            let mut sha = sha1::Sha1::new();
            sha.input(src.as_slice());
            let res = sha.result_str();
            Ok(res)
        });
        methods.add_method("sha256",|_,_,src:Vec<u8>|{
            let mut sha = sha2::Sha256::new();
            sha.input(src.as_slice());
            let res = sha.result_str();
            Ok(res)
        });
        methods.add_method("sha512",|_,_,src:Vec<u8>|{
            let mut sha = sha2::Sha512::new();
            sha.input(src.as_slice());
            let res = sha.result_str();
            Ok(res)
        });
        // methods.add_method("shake128",|_,_,src:Vec<u8>|{
        //     let mut sha = sha3::Sha3::new(Sha3Mode::Shake128);
        //     sha.input(src.as_slice());
        //     let mut buf = vec![0u8;64];
        //     sha.result(buf.as_mut_slice());
        //     Ok(buf.as_str())
        // });
        methods.add_method("hmac",|_,_,src:Vec<u8>|{
            Ok(Hash::new(src))
        });
    }
}